#!/bin/env python

from generator.grammar   import *
from generator.generator import *
from parser.lexer     import Mapper
from parser.reader    import *
from fuzzer import *

cDigit   = SymbolType("cDigit")
cAlpha   = SymbolType("cAlpha")
cSpace   = SymbolType("cSpace")
cComma   = SymbolInstance("c,")
cColon   = SymbolInstance("c:")
cNewLine = SymbolInstance("cNew Line")
cOpenPar = SymbolInstance("c(")
cClosePar = SymbolInstance("c)")
cAlt     = SymbolInstance("c|")
cEq      = SymbolInstance("c=")
cLt      = SymbolType("c<")
cGt      = SymbolInstance("c>")
cMinus   = SymbolInstance("c-")
cQuote   = SymbolInstance("c\"")
cBSlash  = SymbolInstance("c\\")
cN       = SymbolInstance("cn")
cDot     = SymbolInstance("c.")
cOther   = SymbolType("cOther")
cEnd     = SymbolType("cEnd")
cTilda   = SymbolType("c~")
cHash    = SymbolType("c#")
cStar    = SymbolType("c*")
cExcl    = SymbolType("c!")
cOpenCB  = SymbolType("c{")
cCloseCB = SymbolType("c}")
cOpenSB  = SymbolType("c[")
cCloseSB = SymbolType("c]")
cDollar  = SymbolType("c$")

classes = {
    cDigit          : "0123456789",
    cAlpha          : "_abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
    cSpace          : " \t\r",
    cComma          : ",",
    cColon          : ":",
    cNewLine        : "\n",
    cOpenPar        : "(",
    cClosePar       : ")",
    cOpenCB         : "{",
    cCloseCB        : "}",
    cOpenSB         : "[",
    cCloseSB        : "]",
    cMinus          : "-",
    cDollar         : "$",
    cAlt            : "|",
    cEq             : "=",
    cLt             : "<",
    cGt             : ">",
    cQuote          : "\"",
    cBSlash         : "\\",
    cN              : "n",
    cDot            : ".",
    cTilda          : "~",
    cHash           : "#",
    cStar           : "*",
    cExcl           : "!",
    SymbolType.tEnd : ""
}

tId      = SymbolType("[Id]")
tStr     = SymbolType("[String]")
tNumber  = SymbolType("Num")
t10Number  = SymbolType(".Num")
tIs      = SymbolInstance("=>")
tComma   = SymbolInstance(",")
tAlt     = SymbolInstance("|")
tColon   = SymbolInstance(":")
tOpenPar = SymbolInstance("(")
tClosePar= SymbolInstance(")")
tOpenCB  = SymbolInstance("{")
tCloseCB = SymbolInstance("}")
tOpenSB  = SymbolInstance("[")
tCloseSB = SymbolInstance("]")
tOpenVar = SymbolInstance("${")
tNewLine = SymbolInstance("\\n")
tEscNewLine = SymbolInstance("\\\\n")
tSpace   = SymbolType("[Space]")
tEnd     = SymbolType.tEnd
lElement = SymbolType("LexerElement")
tIdcont  = SymbolType("[Id-cont]")
tStrcont = SymbolType("[Str-cont]")
tTilda   = SymbolInstance("~")
tHash   = SymbolInstance("t#")
tStar   = SymbolInstance("t*")
tExcl   = SymbolInstance("t!")
tEq     = SymbolInstance("t=")
tLt     = SymbolInstance("t<")
tGt     = SymbolInstance("t>")

clId     = SymbolClass("clId", cAlpha, cN, cMinus)
clIdCont = SymbolClass("clIdCont", cAlpha, cN, cMinus, cDigit)
clEsc    = SymbolClass("clEsc", cQuote, cBSlash, cN)

lexerGrammar = Grammar(
    P(
        Rule(lElement, [tId                      ]),
        Rule(lElement, [tIs                      ]),
        Rule(lElement, [tColon                   ]),
        Rule(lElement, [tComma                   ]),
        Rule(lElement, [tTilda                   ]),
        Rule(lElement, [tHash                    ]),
        Rule(lElement, [tStar                    ]),
        Rule(lElement, [tExcl                    ]),
        Rule(lElement, [tNewLine                 ]),
        Rule(lElement, [tEscNewLine              ]),
        Rule(lElement, [tOpenPar                 ]),
        Rule(lElement, [tClosePar                ]),
        Rule(lElement, [tOpenCB                  ]),
        Rule(lElement, [tCloseCB                 ]),
        Rule(lElement, [tOpenSB                  ]),
        Rule(lElement, [tOpenVar                 ]),
        Rule(lElement, [tCloseSB                 ]),
        Rule(lElement, [tSpace                   ]),
        Rule(lElement, [tNumber                  ]),
        Rule(lElement, [tEq                      ]),
        Rule(lElement, [tLt                      ]),
        Rule(lElement, [tGt                      ]),
        Rule(lElement, [                         ], lambda value: tEnd.create(value)  ),
        Rule(tOpenPar, [cOpenPar                 ], lambda value: tOpenPar.create(value) ),
        Rule(tClosePar,[cClosePar                ], lambda value: tClosePar.create(value) ),
        Rule(tOpenVar, [cDollar, cOpenPar        ], lambda value: tOpenVar.create(value) ),
        Rule(tOpenCB,  [cOpenCB                  ], lambda value: tOpenCB.create(value) ),
        Rule(tCloseCB, [cCloseCB                 ], lambda value: tCloseCB.create(value) ),
        Rule(tOpenSB,  [cOpenSB                  ], lambda value: tOpenSB.create(value) ),
        Rule(tCloseSB, [cCloseSB                 ], lambda value: tCloseSB.create(value) ),
        Rule(tNumber , [cDigit                   ], lambda value: tNumber.create(int(value))),
        Rule(tNumber , [cDigit  , tNumber        ]),
        Rule(tNumber , [cDigit  , cDot, t10Number]),
        Rule(t10Number , [cDigit                 ], lambda value: tEnd.create(float(value))  ),
        Rule(t10Number , [cDigit  , t10Number    ]),
        Rule(tId,      [clId    , tIdcont        ]),
        Rule(tIdcont,  [                         ], lambda value: tId.create(value)   ),
        Rule(tIdcont,  [clIdCont, tIdcont        ]),
        Rule(tIs,      [cEq, cGt                 ], lambda value: tIs.create(value)   ),
        Rule(tTilda,   [cTilda                   ], lambda value: tTilda.create(value)),
        Rule(tHash ,   [cHash                    ], lambda value: tHash.create(value)),
        Rule(tStar,    [cStar                    ], lambda value: tStar.create(value)),
        Rule(tExcl,    [cExcl                    ], lambda value: tExcl.create(value)),
        Rule(tComma,   [cComma                   ], lambda value: tComma.create(value)),
        Rule(tColon,   [cColon                   ], lambda value: tColon.create(value)),
        Rule(tNewLine, [cNewLine                 ], lambda value: tNewLine.create(value)),
        Rule(tEscNewLine, [cBSlash, cNewLine     ], lambda value: tEscNewLine.create(value)),
        Rule(tAlt,     [cAlt                     ]),
        Rule(tSpace,   [cSpace                   ], lambda value: tSpace.create(value)),
        Rule(tEq   ,   [cEq                      ], lambda value: tEq.create(value)),
        Rule(tLt   ,   [cLt                      ], lambda value: tLt.create(value)),
        Rule(tGt   ,   [cGt                      ], lambda value: tGt.create(value)),
        Rule(tSpace,   [cBSlash, cNewLine        ], lambda value: tSpace.create(value)),
        Rule(tSpace,   [cSpace , tSpace          ]),
        Rule(tSpace,   [cBSlash, cNewLine, tSpace])
    ),
    lElement
)


nDef  = SymbolType("nDef")
nRule = SymbolType("nRule")
nRules = SymbolType("nRules")
nMods = SymbolType("nMods")
nMod = SymbolType("nMod")
nRates = SymbolType("nRates")
nSubset = SymbolType("nSubset")
nRepeat = SymbolType("nRepeat")
nAtom = SymbolType("nAtom")
nVar = SymbolType("nVar")
nFunction = SymbolType("nFunction")
nArgs = SymbolType("nArgs")
nSet = SymbolType("nSet")
nItems = SymbolType("nItems")
nItem = SymbolType("nItem")
nRate = SymbolType("nRate")
nChars = SymbolType("nChars")
nChar = SymbolType("nChar")
# tclAtom = SymbolClass("tclAtom", tId, tSpace, tNumber)
nLit  = SymbolType("nLiteral")

parserGrammar = Grammar(P(
    Rule(nDef     , [nRules                 ], lambda ctxt, r    : r),
    Rule(nRules   , [                       ], lambda ctxt       : Empty()),
    Rule(nRules   , [nRule  , nRules        ], lambda ctxt, r, rs: rs.append(r)),
    Rule(nRule    , [nAtom                  ], lambda ctxt, a    : a),
    Rule(nRule    , [nRule  , tTilda , nAtom], lambda ctxt, a, m : m.rates(a)),
    Rule(nRule    , [nRule  , tHash  , nAtom], lambda ctxt, a, m : m.subset(a)),
    Rule(nRule    , [nRule  , tStar  , nAtom], lambda ctxt, a, m : m.repeat(a)),
    Rule(nAtom    , [nLit                   ], lambda ctxt, s    : s),
    Rule(nLit     , [tId                    ], lambda ctxt, s    : Id(s)),
    Rule(nLit     , [tSpace                 ], lambda ctxt, s    : Space(s)),
    Rule(nLit     , [tNumber                ], lambda ctxt, s    : Number(s)),
    Rule(nAtom    , [nVar                   ], lambda ctxt, v    : Var(v)),
    Rule(nAtom    , [nFunction              ], lambda ctxt, f    : f),
    Rule(nAtom    , [nSet                   ], lambda ctxt, s    : s),
    Rule(nArgs    , [nAtom                  ], lambda ctxt, a    : Args(a)),
    Rule(nArgs    , [nAtom, nArgs           ], lambda ctxt, a, ag: ag.insert(a)),
    Rule(nItem    , [nRules,tOpenPar, tNumber, tClosePar         ], lambda ctxt, r, o, rt, c: Item(r, rt)),
    Rule(nItem    , [nRules                                      ], lambda ctxt, r          : Item(r)),
    Rule(nChar    , [nLit, tOpenPar, tNumber, tClosePar          ], lambda ctxt, s, o, r, c : Item(s, r)),
    Rule(nChar    , [nLit                                        ], lambda ctxt, s          : Item(s)),
    Rule(nItems   , [nItem                                       ], lambda ctxt, i          : Set(i)),
    Rule(nVar     , [tOpenVar, tId, tCloseCB                     ], lambda ctxt, o, i, c    : Var(i)),
    Rule(nVar     , [tOpenVar, tId, tColon, nRule, tCloseCB      ], lambda ctxt, o, i, cl, val, c: Var(i, val)),
    Rule(nVar     , [tOpenVar, tId, tColon, tEq, nRule, tCloseCB ], lambda ctxt, o, i, cl, eq, val, c: i),
    Rule(nVar     , [tOpenVar, tId, tEq, nRule, tCloseCB         ], lambda ctxt, o, i, eq, val, c: i),
    Rule(nFunction, [tExcl, tId, tOpenPar, tClosePar             ], lambda ctxt, e, i, o, c: Function(i)),
    Rule(nFunction, [tExcl, tId, tOpenPar, nArgs, tClosePar      ], lambda ctxt, e, i, o, args, c: Function(i, args)),
    Rule(nSet     , [tOpenCB, nItems, tCloseCB                   ], lambda ctxt, o, its, c: its),
    Rule(nSet     , [tLt, nItem, tComma, nItem, tGt              ], lambda ctxt, o, st, cm, en, c: Range(st, en)),
    Rule(nSet     , [tOpenSB, nChars, tCloseSB                   ], lambda ctxt, o, ch, c: ch),
    Rule(nSet     , [tOpenSB, tColon, tId, tColon, tCloseSB      ], lambda ctxt, o, co, i, cc, c: i),
    Rule(nItems   , [nItem, tComma, nItems                       ], lambda ctxt, i, c, s: s.insert(i)),
    Rule(nChars   , [                                            ], lambda ctxt         : Chars()),
    Rule(nChars   , [nChar, nChars                               ], lambda ctxt, c, s   : s.insert(c)),
), nDef, I(tEscNewLine))

mapper = Mapper(classes, cOther)
lexer  = Lexer(LexerGenerator(lexerGrammar).getStates(), mapper)
parser = Parser(ParserGenerator(parserGrammar).getStates(), lexer)
g = parser.parse(String('a {co,se,3,deje(4)}[aeiou]'), None)
import sys
g.fuzz(sys.stdout)
print